﻿#include <iostream>
#include <vector>
#include <list>
#include <deque>
#include <algorithm>

using namespace std;

// c++ 中的继承
// 我们看以下学校信息管理系统的学生类和老师类
// 在大部分的信息方面是一致的，如果这样分成两个类都实现有点冗余

#if 0
class Student
{
public:
	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
	void identity()
	{
		// ...
	} 

	// 学习
	void study()
	{
		// ...
	}

protected:
	string _name = "欧阳";
	string _address;
	string _tel;
	int _age = 19;

	int _stuid;
};

class Teacher
{
public:
	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
	void identity()
	{
		// ...
	} 
	// 授课
	void teaching()
	{
		//...
	}
protected:
	string _name = "欧阳";
	string _address;
	string _tel;
	int _age = 19;

	string _title;
};


// 我们只需定义一个Person类，将公共成员放入其中，然后继承复用即可
class Person
{
public:
	// 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
	void identity()
	{
		cout << "void identity()" << endl;
		// ...
	}
protected:
	string _name = "欧阳";	// 姓名
	string _address;		// 地址
	string _tel;			// 电话
	int _age = 19;			// 年龄
};

class Student : public Person
{
public:
	// 学习
	void study()
	{
		cout << "void study()" << endl;
		// ...
	}
protected:
	int _stuid; // 学号
};

class Teacher : public Person
{
public:
	// 授课
	void teaching()
	{
		cout << "void teaching()" << endl;
		//...
	}
protected:
	string _title;	//职位
};

int main()
{
	Student s;
	Teacher t;

	s.identity();
	s.study();

	t.identity();
	t.teaching();

	return 0;
}


// 继承类的模版
namespace ouyang
{
	template<class T>
	class stack : public std::vector<T>
	{
	public:
		void push(const T& x)
		{
			//push_back(x);// err
			// 一定要对象实例化
			// ⽗类是类模板时，需要指定⼀下类域，
			// 否则编译报错:error C3861: “push_back”: 找不到标识符
			// 因为stack<int>实例化时，也实例化vector<int>了
			// 但是模版是按需实例化，push_back等成员函数未实例化，所以找不到
			vector<T>::push_back(x);
		}
		void pop()
		{
			vector<T>::pop_back();
		}

		const T& top()
		{
			return vector<T>::back();
		}

		bool empty()
		{
			return vector<T>::empty();
		}
	};
}

int main()
{
	ouyang::stack<int> st;
	st.push(1);
	st.push(2);
	st.push(3);
	while (!st.empty())
	{
		cout << st.top() << " ";
		st.pop();
	}

	return 0;
}


class Parents
{
protected:
	string _name;
	string _sex;
	int _age;
};

class Child : public Parents
{
public:
	int _nature; // 性格
};

int main()
{
	Child cd;

	// 1.⼦类对象可以赋值给⽗类对象 / 指针 / 引⽤
	Parents pt = cd;
	Parents* pp = &cd;
	Parents& rp = cd;

	// 2.⽗类对象不能赋值给⼦类对象，这⾥会编译报错
	// err
	//cd = pt;

	return 0;
}


// 继承中的隐藏
class Parents
{
protected:
	string _name;
	string _sex;
	int _age;
	int _num = 100;
};

class Child : public Parents
{
public:
	void Print()
	{
		cout << _num << endl;
		cout << Parents::_num << endl;
	}
protected:
	int _nature; // 性格
	int _num = 888;
};

int main()
{
	Child cd;
	// 这边因该输出父类的_num还是子类的_num?
	// 隐藏规则：
	/*1. 在继承体系中⽗类和⼦类都有独⽴的作⽤域。
	  2.⼦类和⽗类中有同名成员，⼦类成员将屏蔽⽗类对同名成员的直接访问，这种情况叫隐藏。
	  （在⼦类成员函数中，可以使⽤⽗类::⽗类成员显⽰访问）
	  3. 需要注意的是如果是成员函数的隐藏，只需要函数名相同就构成隐藏。
	  4. 注意在实际中在继承体系⾥⾯最好不要定义同名的成员。*/
	cd.Print();
	return 0;
}

/*A和B类中的两个func构成什么关系（）
A.重载 B.隐藏 C.没关系*/
/*下⾯程序的编译运⾏结果是什么（）
A.编译报错 B.运⾏报错 C.正常运⾏*/
class A
{
	public :
	void fun()
	{
		cout << "func()" << endl;
	}
};

class B : public A
{
	public :
	void fun(int i)
	{
		cout << "func(int i)" << i << endl;
	}
};

// [1] 首先不构成重载关系，重载的前置条件是在同一作用域，只要是函数名相同就是隐藏关系，不论参数
// [2] 编译报错，因为构成了隐藏关系所以b.fun()调用的是子类的函数，但是没有传参
int main()
{
	B b;
	b.fun(10);
	//b.fun();  err
	b.A::fun();
	return 0;
};


// 子类的默认成员函数
// 当然对于没有资源的类我们使用编译器默认生成的即可
// 下面模拟需要清理资源的类

class Parents
{
public:
	Parents(const char* name = "欧阳")
		:_name(name)
	{
		cout << "Parents(const char* name = \"欧阳\" " << endl;
	}

	Parents(const Parents& Ps)
		:_name(Ps._name)
	{
		cout << "Parents(const Parents& Ps)" << endl;
	}

	Parents& operator=(const Parents& Ps)
	{ 
		cout << "Parents& operator=(const Parents& Ps)" << endl;
		if (this != &Ps)
		{
			_name = Ps._name;
		}

		return *this;
	}

	~Parents()
	{
		cout << "~Parents()" << endl;
	}
protected:
	string _name;
};

class Child : public Parents
{
public:
	// 默认生成的构造函数的行为
	// 1、内置类型->不确定
	// 2、自定义类型->调用默认构造
	// 3、继承父类成员看做一个整体对象，要求调用父类的默认构造

	/*⼦类的构造函数必须调⽤⽗类的构造函数初始化⽗类的那⼀部分成员。如果⽗类没有默认的构造函
	数，则必须在⼦类构造函数的初始化列表阶段显⽰调⽤。*/
	Child(const char* name, int age)
		:Parents(name)
		,_age(age)
	{	
		cout << "Child(const char* name, int age)" << endl;
	}

	/*⼦类的拷⻉构造函数必须调⽤⽗类的拷⻉构造完成⽗类的拷⻉初始化。*/
	Child(const Child& cd)
		: Parents(cd)
		, _age(cd._age)
	{
		cout << "Child(const Child& cd)" << endl;
	}

	/*⼦类的operator=必须要调⽤⽗类的operator=完成⽗类的复制。需要注意的是⼦类的operator=隐
     藏了⽗类的operator=，所以显⽰调⽤⽗类的operator=，需要指定⽗类作⽤域*/
	Child& operator=(const Child& cd)
	{
		cout << "Child& operator=(const Child& cd)" << endl;
		if (this != &cd)
		{
			// 构成隐藏需要显示调用
			Parents::operator=(cd);
			_age = cd._age;
		}
		return *this;
	}

	/*⼦类的析构函数会在被调⽤完成后⾃动调⽤⽗类的析构函数清理⽗类成员。
	因为这样才能保证⼦类对象先清理⼦类成员再清理⽗类成员的顺序。*/
	~Child()
	{
		cout << "~Child()" << endl;
		//Parents::~Parents();
		//delete[] _ptr;
	}

protected:
	int _age;
	int* _ptr = new int[10];
};

int main()
{
	Child c1("欧阳", 18);
	Child c2(c1);
	Child c3("牛马", 19);
	c3 = c1;

	return 0;
}
#endif